package org.sergilos.servicemanager;
import org.apache.thrift.TMultiplexedProcessor;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public abstract class AbstractRunnableServiceWrapper implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRunnableServiceWrapper.class);
protected TServer server;
protected String serviceName;
private ApplicationContext applicationContext;
private TMultiplexedProcessor multiplexedProcessor;
public AbstractRunnableServiceWrapper(ApplicationContext applicationContext, String serviceName) {
LOGGER.debug("Service setup: {}", serviceName);
this.multiplexedProcessor = new TMultiplexedProcessor();
this.applicationContext = applicationContext;
this.serviceName = serviceName;
}
public void addProcessor(String serviceHandlerClass, String processorNameClass) {
multiplexedProcessor.registerProcessor(processorNameClass, getProcess(serviceHandlerClass, processorNameClass));
}
public void initializeServer() throws TTransportException {
server = getServer(multiplexedProcessor);
}
@SuppressWarnings("unchecked")
private <T extends TProcessor> T getProcess(String serviceHandlerClass, String processorNameClass) {
T processor = null;
try {
Class<?> handlerClass = Class.forName(serviceHandlerClass);
Class<T> processorClass = (Class<T>) getProcessorClass(Class.forName(processorNameClass));
Constructor<T> processorConstructor = (Constructor<T>) processorClass.getConstructors()[0];
processor = processorConstructor.newInstance(getHandlerInstance(handlerClass));
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SecurityException | IllegalArgumentException
| InvocationTargetException e) {
LOGGER.error("Error instantiating processor", e);
}
return processor;
}
private <T> T getHandlerInstance(Class<T> handler) throws InstantiationException, IllegalAccessException {
T handlerInstance = handler.newInstance();
if (this.applicationContext != null) {
LOGGER.debug("Autowiring {}", handlerInstance.getClass().getSimpleName());
this.applicationContext.getAutowireCapableBeanFactory().autowireBean(handlerInstance);
}
return handlerInstance;
}
private Class<?> getProcessorClass(Class<?> processorOuterClass) {
for (Class<?> referencedClass : processorOuterClass.getClasses()) {
if (referencedClass.getSimpleName().equals("Processor")) {
return referencedClass;
}
}
return null;
}
@Override
public void run() {
LOGGER.info("Start Service '{}'", serviceName);
try {
initializeServer();
this.startService();
} catch (TTransportException e) {
LOGGER.error("Error initializing service " + serviceName, e);
} catch (Exception e) {
LOGGER.error("Unexpected exception on Thirft Service", e);
} finally {
LOGGER.debug("Service thread closing {}", serviceName);
}
}
public void stopService() {
if (server != null && server.isServing()) {
LOGGER.debug("Stop Service thread {}", serviceName);
server.stop();
}
}
public void startService() {
if (!server.isServing()) {
server.serve();
}
}
protected abstract TServer getServer(TProcessor processor) throws TTransportException;
public static abstract class ServiceWrapperFactory {
public abstract AbstractRunnableServiceWrapper getServiceServerWrapper(ApplicationContext applicationContext, String serviceName, Integer port);
public abstract TProtocol getClientProtocol(String serviceInterfaceClassName, String host, Integer port) throws TTransportException;
}
}